<?php

/**
 * This file is part of Webman AI.
 *
 * @author    walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link      http://www.workerman.net/
 */

namespace plugin\ai\app\event\listener;

use plugin\admin\app\common\Util;
use plugin\ai\api\Chat;
use plugin\ai\app\event\data\EventData;
use plugin\ai\app\event\data\ModelRequestData;
use plugin\ai\app\event\data\ModelResponseData;
use plugin\ai\app\service\Common;
use plugin\ai\app\service\Setting;
use Webman\Event\Event;

class ModelRequest
{
    /**
     * gpt伪装
     * @param ModelRequestData $obj
     * @return void
     */
    public function gptMask(ModelRequestData $obj)
    {
        $data = $obj->data;
        $model = $data['model'];
        $messages = $data['messages'] ?? [];
        if (strpos($model, 'gpt') === 0 && $mask = Setting::getSetting('gpt_mask')) {
            $version = '3.5';
            if (preg_match('/\d+(\.\d+)?/', $model, $matches)) {
                $version = $matches[0];
            }
            $mask = str_replace('{version}', $version, $mask);
            if ($messages[0]['role'] !== 'system') {
                $messages = array_merge([[
                    'role' => 'system',
                    'content' => $mask,
                ]], $messages);
            } else {
                $messages[0]['content'] = "$mask\n" . $messages[0]['content'];
            }
            $data['messages'] = $messages;
        }
        $obj->data = $data;
    }

    /**
     * 让gpt联网
     * @param ModelRequestData $obj
     * @return void
     */
    public function network(ModelRequestData $obj)
    {
        $data = $obj->data;
        $model = $data['model'];
        // 尝试开启 function call 联网
        $openaiVersion = Util::getPackageVersion('webman/openai');
        $networkRequest = $data['networkRequest'] ?? false;
        unset($data['networkRequest']);
        $modelInfo = Common::getModelInfo($model);
        $networkSearchModelName = $modelInfo->settings['networkModel']['value'] ?? '';
        $allowNetwork = $modelInfo->settings['allowNetwork']['value'] ?? false;
        if (!$networkRequest && $allowNetwork && $networkSearchModelName && $openaiVersion !== 'unknown' && version_compare($openaiVersion, '1.0.7', '>=')) {
            $data['tools'] = [[
                'type' => 'function',
                'function' => [
                    'name' => 'internet_search',
                    'description' => "提供互联网实时信息，例如热点新闻、最近天气、当前时间",
                    'parameters' => [
                        'type' => 'object',
                        'properties' => [
                            'keywords' => [
                                'type' => 'string',
                                'description' => 'Keywords to search for',
                            ]
                        ]
                    ]
                ]
            ]];
            $options = $obj->options;
            if ($options['complete']) {
                $complete = $options['complete'];
                $options['complete'] = function($result, $response) use ($data, $networkSearchModelName, $obj, $complete) {
                    if (!isset($result['error'])) {
                        if (is_array($result) && ($result['function']['name'] ?? '') === 'internet_search') {
                            unset($data['tools']);
                            $data['model'] = $networkSearchModelName;
                            $data['networkRequest'] = true;
                            $obj->data = $data;
                            Event::dispatch('ai.chat.completions.request', $obj);
                            try {
                                Chat::completions($obj->data, $obj->options);
                            } catch (\Throwable $e) {
                                $complete(['error' => ['message' => $e->getMessage()]], null);
                            }
                            return;
                        }
                    }
                    call_user_func($complete, $result, $response);
                };
                $obj->options = $options;
            }
        }
        $obj->data = $data;
    }

    public function dalleCdnReplace(ModelResponseData $obj)
    {
        $model = $obj->modelRequestData->data['model'];
        if (strpos($model, 'dall') === 0 && $url = $obj->data['data'][0]['url'] ?? '') {
            $obj->data['data'][0]['url'] = '/app/ai/image/get?model=dalle&date=' . date('Ymd') . '&url=' . urlencode($url);
        }
    }

    public function midjourneyStatusCdnReplace(ModelResponseData $obj)
    {
        $progress = $obj->data['data']['progress'] ?? '';
        $url = $obj->data['data']['imageUrl'] ?? '';
        if ($progress === '100%' && $url) {
            $obj->data['data']['imageUrl'] = '/app/ai/image/get?model=midjourney&date=' . date('Ymd') . '&url=' . urlencode($url);
            $obj->data['data']['smallUrl'] = '/app/ai/image/get?type=sm&model=midjourney&date=' . date('Ymd') . '&url=' . urlencode($url);
            $obj->data['data']['thumbUrl'] = '/app/ai/image/get?type=thumb&model=midjourney&date=' . date('Ymd') . '&url=' . urlencode($url);
        }
    }

    public function midjourneyNotifyCdnReplace(EventData $obj)
    {
        $progress = $obj->data['progress'] ?? '';
        $url = $obj->data['imageUrl'] ?? '';
        if ($progress === '100%' && $url) {
            $obj->data['imageUrl'] = '/app/ai/image/get?model=midjourney&date=' . date('Ymd') . '&url=' . urlencode($url);
            $obj->data['smallUrl'] = '/app/ai/image/get?type=sm&model=midjourney&date=' . date('Ymd') . '&url=' . urlencode($url);
            $obj->data['thumbUrl'] = '/app/ai/image/get?type=thumb&model=midjourney&date=' . date('Ymd') . '&url=' . urlencode($url);
        }
    }

}